﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Buccontrols
{
    #region Enums

    public enum DragFormResult { Return = 0, Close = 1, Options = 2, Add = 3, Cancel = 4 }

    #endregion

    public partial class DragForm : Form
    {
        #region Declarations

        private bool drag = false;
        private Point mouseStartLoc;
        private Rectangle formStartArea;
        private bool draggable = true;
        private string exclude_list = "";
        private Rectangle bounds;
        public DragFormResult result = DragFormResult.Return;
        public string resizeDirection = "left";

        #endregion

        #region Constructor

        public DragForm(Rectangle bounds, Point location, Size size)
        {
            this.SetStyle(
                ControlStyles.AllPaintingInWmPaint |
                ControlStyles.UserPaint |
                ControlStyles.DoubleBuffer, true);

            InitializeComponent();
            
            this.bounds = bounds;
            this.StartPosition = FormStartPosition.Manual;
            this.Size = size;
            this.Location = location;
            this.mouseStartLoc = Cursor.Position;
            this.formStartArea = new Rectangle(this.Location, this.Size);
            this.ExcludeList = "top, bottom, left, right";

            Point p5 = this.PointToClient(new Point(MousePosition.X, MousePosition.Y));
            Form_MouseDown(this, new MouseEventArgs(MouseButtons.Middle, 1, p5.X, p5.Y, 0));

            AddBorders();
            AddButtons();

            this.BackgroundImage = Options.GetResource("dragFormBack") as Image;
        }

        #region Borders

        private void AddBorders()
        {
            this.SuspendLayout();

            this.borderLeft = new Panel();
            this.borderRight = new Panel();
            this.borderTop = new Panel();
            this.borderBottom = new Panel();
            //
            //borderLeft
            //
            this.borderLeft.Anchor = AnchorStyles.Left;
            this.borderLeft.BackgroundImage = Options.GetResource("dragFormBorderLeft") as Image;
            this.borderLeft.BackgroundImageLayout = ImageLayout.Stretch;
            this.borderLeft.Cursor = Cursors.VSplit;
            this.borderLeft.Location = new Point(0, 40);
            this.borderLeft.MouseDown += new MouseEventHandler(border_MouseDown);
            this.borderLeft.Name = "left";
            this.borderLeft.Size = new Size(27, this.Size.Height - 80);
            //
            //borderRight
            //
            this.borderRight.Anchor = AnchorStyles.Right;
            this.borderRight.AutoSize = false;
            this.borderRight.BackgroundImage = Options.GetResource("dragFormBorderRight") as Image;
            this.borderRight.BackgroundImageLayout = ImageLayout.Stretch;
            this.borderRight.Cursor = Cursors.VSplit;
            this.borderRight.Location = new Point(this.Size.Width - 27, 40);
            this.borderRight.MouseDown += new MouseEventHandler(border_MouseDown);
            this.borderRight.Name = "right";
            this.borderRight.Size = new Size(27, this.Size.Height - 80);
            //
            //borderTop
            //
            this.borderTop.Anchor = AnchorStyles.Top;
            this.borderTop.AutoSize = false;
            this.borderTop.BackgroundImage = Options.GetResource("dragFormBorderTop") as Image;
            this.borderTop.BackgroundImageLayout = ImageLayout.Stretch;
            this.borderTop.Cursor = Cursors.HSplit;
            this.borderTop.Location = new Point(40, 0);
            this.borderTop.MouseDown += new MouseEventHandler(border_MouseDown);
            this.borderTop.Name = "top";
            this.borderTop.Size = new Size(this.Size.Width - 80, 27);
            //
            //borderBottom
            //
            this.borderBottom.Anchor = AnchorStyles.Bottom;
            this.borderBottom.BackgroundImage = Options.GetResource("dragFormBorderBottom") as Image;
            this.borderBottom.BackgroundImageLayout = ImageLayout.Stretch;
            this.borderBottom.Cursor = Cursors.HSplit;
            this.borderBottom.Location = new Point(40, this.Size.Height - 27);
            this.borderBottom.MouseDown += new MouseEventHandler(border_MouseDown);
            this.borderBottom.Name = "bottom";
            this.borderBottom.Size = new Size(this.Size.Width - 80, 27);
            //
            //Add borders to Controls
            //
            this.Controls.Add(borderLeft);
            this.Controls.Add(borderRight);
            this.Controls.Add(borderTop);
            this.Controls.Add(borderBottom);

            this.ResumeLayout(false);
        }

        private void RefreshBorders()
        {
            this.SuspendLayout();

            this.borderLeft.Location = new Point(0, 40);
            this.borderLeft.Size = new Size(27, this.Size.Height - 80);
            this.borderRight.Location = new Point(this.Size.Width - 27, 40);
            this.borderRight.Size = new Size(27, this.Size.Height - 80);
            this.borderTop.Location = new Point(40, 0);
            this.borderTop.Size = new Size(this.Size.Width - 80, 27);
            this.borderBottom.Location = new Point(40, this.Size.Height - 27);
            this.borderBottom.Size = new Size(this.Size.Width - 80, 27);

            this.ResumeLayout(false);
        }

        private void border_MouseDown(object sender, MouseEventArgs e)
        {
            this.mouseStartLoc = Cursor.Position;
            this.formStartArea = new Rectangle(this.Location, this.Size);
            this.resizeDirection = (sender as Panel).Name;
            Thread td = new Thread(new ThreadStart(resizeForm));
            td.Start();
        }

        private Panel borderLeft;
        private Panel borderRight;
        private Panel borderTop;
        private Panel borderBottom;

        #endregion

        #region Buttons

        private void AddButtons()
        {
            this.SuspendLayout();

            this.buttonBack = new BitmapButton();
            this.buttonClose = new BitmapButton();
            this.buttonOptions = new BitmapButton();
            this.buttonAdd = new BitmapButton();
            //
            //buttonBack
            //
            this.buttonBack.Anchor = AnchorStyles.Top | AnchorStyles.Left;
            this.buttonBack.BackgroundImage = Options.GetResource("dragFormButtonBack") as Image;
            this.buttonBack.Size = this.buttonBack.BackgroundImage.Size;
            this.buttonBack.Location = new Point(0, 0);
            this.buttonBack.Click += new EventHandler(buttonBack_Click);
            this.buttonBack.Cursor = Cursors.Hand;
            //
            //buttonClose
            //
            this.buttonClose.Anchor = AnchorStyles.Top | AnchorStyles.Right;
            this.buttonClose.BackgroundImage = Options.GetResource("dragFormButtonClose") as Image;
            this.buttonClose.Size = this.buttonClose.BackgroundImage.Size;
            this.buttonClose.Location = new Point(this.Width - this.buttonClose.Width, 0);
            this.buttonClose.Click += new EventHandler(buttonClose_Click);
            this.buttonClose.Cursor = Cursors.Hand;
            //
            //buttonOptions
            //
            this.buttonOptions.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
            this.buttonOptions.BackgroundImage = Options.GetResource("dragFormButtonOptions") as Image;
            this.buttonOptions.Size = this.buttonOptions.BackgroundImage.Size;
            this.buttonOptions.Location = new Point(this.Width - this.buttonOptions.Width, this.Height - this.buttonOptions.Height);
            this.buttonOptions.Click += new EventHandler(buttonOptions_Click);
            this.buttonOptions.Cursor = Cursors.Hand;
            //
            //buttonAdd
            //
            this.buttonAdd.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
            this.buttonAdd.BackgroundImage = Options.GetResource("dragFormButtonAdd") as Image;
            this.buttonAdd.Size = this.buttonAdd.BackgroundImage.Size;
            this.buttonAdd.Location = new Point(0, this.Height - this.buttonAdd.Height);
            this.buttonAdd.Click += new EventHandler(buttonAdd_Click);
            this.buttonAdd.Cursor = Cursors.Hand;
            //
            //Add borders to Controls
            //
            this.Controls.Add(buttonBack);
            this.Controls.Add(buttonClose);
            this.Controls.Add(buttonOptions);
            this.Controls.Add(buttonAdd);
            
            this.ResumeLayout(false);
        }

        private BitmapButton buttonBack;
        private BitmapButton buttonClose;
        private BitmapButton buttonOptions;
        private BitmapButton buttonAdd;

        private void buttonBack_Click(object sender, EventArgs e)
        {
            this.result = DragFormResult.Cancel;
            this.Close();
        }

        private void buttonClose_Click(object sender, EventArgs e)
        {
            this.result = DragFormResult.Close;
            this.Close();
        }

        private void buttonOptions_Click(object sender, EventArgs e)
        {
            this.result = DragFormResult.Options;
            this.Close();
        }

        private void buttonAdd_Click(object sender, EventArgs e)
        {
            this.result = DragFormResult.Add;
            this.Close();
        }

        #endregion

        #endregion

        #region resize

        private void resizeForm()
        {
            Size formSize = this.Size;
            Point formLocation = this.Location;
            Rectangle formArea = new Rectangle(formLocation, formSize);
            while (Control.MouseButtons == MouseButtons.Left)
            {
                switch (resizeDirection)
                {
                    case "left":
                        this.Invoke((MethodInvoker)delegate
                        {
                            formSize = new Size(formLocation.X - Cursor.Position.X + this.Width, this.Height);
                            formLocation = new Point(Cursor.Position.X, formLocation.Y);
                            formArea = new Rectangle(formLocation, formSize);
                            if (bounds.Contains(formArea))
                            {
                                if (formSize.Height < this.MinimumSize.Height)
                                    formSize.Height = this.MinimumSize.Height;
                                if (formSize.Width < this.MinimumSize.Width)
                                    formSize.Width = this.MinimumSize.Width;
                                this.Size = formSize;
                                this.Location = formLocation;
                                this.RefreshBorders();
                                this.Refresh();
                                this.Update();
                                this.PerformLayout();
                            }
                        });
                        break;
                    case "right":
                        this.Invoke((MethodInvoker)delegate
                        {
                            formSize = new Size(Cursor.Position.X - formLocation.X, this.Height);
                            formArea = new Rectangle(formLocation, formSize);
                            if (bounds.Contains(formArea))
                            {
                                if (formSize.Height < this.MinimumSize.Height)
                                    formSize.Height = this.MinimumSize.Height;
                                if (formSize.Width < this.MinimumSize.Width)
                                    formSize.Width = this.MinimumSize.Width;
                                this.Size = formSize;
                                this.RefreshBorders();
                                this.Refresh();
                                this.Update();
                                this.PerformLayout();
                            }
                        });
                        break;
                    case "top":
                        this.Invoke((MethodInvoker)delegate
                        {
                            formSize = new Size(this.Width, formLocation.Y - Cursor.Position.Y + this.Height);
                            formLocation = new Point(formLocation.X, Cursor.Position.Y);
                            formArea = new Rectangle(formLocation, formSize);
                            if (bounds.Contains(formArea))
                            {
                                if (formSize.Height < this.MinimumSize.Height)
                                    formSize.Height = this.MinimumSize.Height;
                                if (formSize.Width < this.MinimumSize.Width)
                                    formSize.Width = this.MinimumSize.Width;
                                this.Size = formSize;
                                this.Location = formLocation;
                                this.RefreshBorders();
                                this.Refresh();
                                this.Update();
                                this.PerformLayout();
                            }
                        });
                        break;
                    case "bottom":
                        this.Invoke((MethodInvoker)delegate
                        {
                            formSize = new Size(this.Width, Cursor.Position.Y - formLocation.Y);
                            formArea = new Rectangle(formLocation, formSize);
                            if (bounds.Contains(formArea))
                            {
                                if (formSize.Height < this.MinimumSize.Height)
                                    formSize.Height = this.MinimumSize.Height;
                                if (formSize.Width < this.MinimumSize.Width)
                                    formSize.Width = this.MinimumSize.Width;
                                this.Size = formSize;
                                this.RefreshBorders();
                                this.Refresh();
                                this.Update();
                                this.PerformLayout();
                            }
                        });
                        break;
                }
            }
        }

            #endregion

        #region drag

        private void dragForm()
        {
            try
            {
                Point formLocation = this.Location;
                while (Control.MouseButtons == MouseButtons.Left || Control.MouseButtons == MouseButtons.Middle || Control.MouseButtons == MouseButtons.Right)
                {
                    this.Invoke((MethodInvoker)delegate
                    {
                        Point p2 = Cursor.Position;
                        Point p3 = new Point(
                            Cursor.Position.X - this.mouseStartLoc.X + formLocation.X, 
                            Cursor.Position.Y - this.mouseStartLoc.Y + formLocation.Y);
                        Point p4 = new Point(
                            p3.X < bounds.X 
                                ? bounds.X 
                                : (p3.X + this.Size.Width > bounds.X + bounds.Width 
                                    ? bounds.X + bounds.Width - this.Size.Width 
                                    : p3.X),
                            p3.Y < bounds.Y 
                                ? bounds.Y 
                                : (p3.Y + this.Size.Height > bounds.Y + bounds.Height 
                                    ? bounds.Y + bounds.Height - this.Size.Height 
                                    : p3.Y));
                        this.Location = p4;
                    });
                }
            }
            catch { Thread.CurrentThread.Abort(); }
        }

        #endregion

        #region Overriden Functions

        protected override void OnControlAdded(ControlEventArgs e)
        {
            //
            //Add Mouse Event Handlers for each control added into the form,
            //if Draggable property of the form is set to true and the control
            //name is not in the ExcludeList.Exclude list is the comma seperated
            //list of the Controls for which you do not require the mouse handler 
            //to be added. For Example a button.  
            //
            if (this.Draggable)
            {
                if (this.ExcludeList.IndexOf(e.Control.Name) == -1)
                {
                    e.Control.MouseDown += new MouseEventHandler(Form_MouseDown);
                    
                }
                e.Control.MouseUp += new MouseEventHandler(Form_MouseUp);
                e.Control.MouseMove += new MouseEventHandler(Form_MouseMove);
            }
            base.OnControlAdded(e);
        }

        #endregion

        #region Event Handlers

        void Form_MouseDown(object sender, MouseEventArgs e)
        {
            //
            //On Mouse Down set the flag drag=true and 
            //Store the clicked point to the start_point variable
            //
            /*/
            this.drag = true;
            this.start_point = new Point(e.X, e.Y);
            //*/
            this.formStartArea = new Rectangle(this.Location, this.Size);
            this.mouseStartLoc = Cursor.Position;
            Thread td = new Thread(new ThreadStart(dragForm));
            td.Start();
        }

        void Form_MouseUp(object sender, MouseEventArgs e)
        {
            //
            //Close the form if the middle mousebutton was pressed and dragging started at init
            //
            //*/
            if (e.Button == MouseButtons.Middle && mouseStartLoc != Cursor.Position)
            {
                this.Close();
            }
            //*/
            //
            //Set the drag flag = false;
            //
            //this.drag = false;
            //*/
        }

        void Form_MouseMove(object sender, MouseEventArgs e)
        {
            //
            //If drag = true, drag the form
            //
            /*/
            if (this.drag)
            {
                Point p1 = new Point(e.X, e.Y);
                Point p2 = this.PointToScreen(p1);
                Point p3 = new Point(p2.X - this.start_point.X, p2.Y - this.start_point.Y);
                Point p4 = new Point(
                    p3.X < bounds.X ? bounds.X : (p3.X + this.Size.Width > bounds.X + bounds.Width ? bounds.X + bounds.Width - this.Size.Width : p3.X),
                    p3.Y < bounds.Y ? bounds.Y : (p3.Y + this.Size.Height > bounds.Y + bounds.Height ? bounds.Y + bounds.Height - this.Size.Height : p3.Y));
                this.Location = p4;
            }
            //*/
        }

        void Form_MouseClick(object sender, MouseEventArgs e)
        {
            //
            //Close the form if the middle mousebutton was pressed
            //
            //*/
            if (e.Button == MouseButtons.Middle)
            {
                this.Close();
            }
            //*/
        }

        #endregion

        #region Properties

        public DragFormResult Result
        {
            get { return result; }
        }

        public string ExcludeList
        {
            set
            {
                this.exclude_list = value;
            }
            get
            {
                return this.exclude_list.Trim();
            }
        }

        public bool Draggable
        {
            set
            {
                this.draggable = value;
            }
            get
            {
                return this.draggable;
            }
        }

        #endregion 

    }
}
